import type { BasicColumn, BasicTableProps, TableRowSelection } from "../types/table";
// import { useWindowSizeFn } from "@/hooks/event/useWindowSizeFn";
import { isBoolean } from "@/utils/is";
import { useEffect, useMemo, useRef, useState } from "react";
import { debounce, nextTick } from "@/utils/index";
import { getViewportOffset } from "@/utils/domUtils";

export function useTableScroll(
	propsRef: BasicTableProps,
	tableElRef: HTMLElement | null,
	columnsRef: BasicColumn[],
	rowSelectionRef: TableRowSelection | null,
	getDataSourceRef: Recordable[],
	wrapRef: HTMLElement | null,
	formRef: HTMLElement
) {
	const [tableHeightRef, setTableHeightRef] = useState<number | string>(167);

	const propsRefStore = useRef<BasicTableProps>(propsRef);
	const tableElRefStore = useRef<HTMLElement | null>(tableElRef);
	const getDataSourceRefStore = useRef<Recordable[]>(getDataSourceRef);
	const wrapRefStore = useRef<HTMLElement | null>(wrapRef);
	const formRefStore = useRef<HTMLElement>(formRef);
	// const columnsRefStore = useRef<BasicColumn[]>(columnsRef);

	// Greater than animation time 280
	const debounceRedoHeight = debounce(redoHeight, 100);

	const getCanResize = useMemo(() => {
		const { canResize, scroll } = propsRef;
		return canResize && !(scroll || {}).y;
	}, [propsRef.canResize, propsRef.scroll]);

	useEffect(() => {
		nextTick(() => {
			debounceRedoHeight();
		});
	}, []);

	useEffect(() => {
		debounceRedoHeight();
	}, [getCanResize, getDataSourceRef.length]);

	// useWindowSizeFn(calcTableHeight, { wait: 280 });

	useEffect(() => {
		propsRefStore.current = propsRef;
		tableElRefStore.current = tableElRef;
		getDataSourceRefStore.current = getDataSourceRef;
		wrapRefStore.current = wrapRef;
		formRefStore.current = formRef;
	}, [propsRef, tableElRef, getDataSourceRef]);

	function redoHeight() {
		calcTableHeight();
	}

	function setHeight(height: number) {
		setTableHeightRef(height);
		//  Solve the problem of modal adaptive height calculation when the form is placed in the modal
	}

	// No need to repeat queries
	let paginationEl: HTMLElement | null;
	let footerEl: HTMLElement | null;
	let bodyEl: HTMLElement | null;

	function handleScrollBar(bodyEl: HTMLElement, tableEl: Element) {
		const hasScrollBarY = bodyEl.scrollHeight > bodyEl.clientHeight;
		const hasScrollBarX = bodyEl.scrollWidth > bodyEl.clientWidth;

		if (hasScrollBarY) {
			tableEl.classList.contains("hide-scrollbar-y") && tableEl.classList.remove("hide-scrollbar-y");
		} else {
			!tableEl.classList.contains("hide-scrollbar-y") && tableEl.classList.add("hide-scrollbar-y");
		}

		if (hasScrollBarX) {
			tableEl.classList.contains("hide-scrollbar-x") && tableEl.classList.remove("hide-scrollbar-x");
		} else {
			!tableEl.classList.contains("hide-scrollbar-x") && tableEl.classList.add("hide-scrollbar-x");
		}
	}

	function caclPaginationHeight(tableEl: Element): number {
		const { pagination } = propsRef || propsRefStore.current;
		// Pager height
		let paginationHeight = 2;
		if (!isBoolean(pagination)) {
			paginationEl = tableEl.querySelector(".ant-pagination") as HTMLElement;
			if (paginationEl) {
				const offsetHeight = paginationEl.offsetHeight;
				paginationHeight += offsetHeight || 0;
			} else {
				// TODO First fix 24
				paginationHeight += 24;
			}
		} else {
			paginationHeight = -8;
		}
		return paginationHeight;
	}

	function caclFooterHeight(tableEl: Element): number {
		const { pagination } = propsRef || propsRefStore.current;
		let footerHeight = 0;
		if (!isBoolean(pagination)) {
			if (!footerEl) {
				footerEl = tableEl.querySelector(".ant-table-footer") as HTMLElement;
			} else {
				const offsetHeight = footerEl.offsetHeight;
				footerHeight += offsetHeight || 0;
			}
		}
		return footerHeight;
	}

	function calcHeaderHeight(headEl: Element): number {
		let headerHeight = 0;
		if (headEl) headerHeight = (headEl as HTMLElement).offsetHeight;

		return headerHeight;
	}

	function calcBottomAndPaddingHeight(tableEl: Element, headEl: Element) {
		const { pagination, isCanResizeParent, useSearchForm } = propsRef || propsRefStore.current;
		const wrapRefDef = wrapRef || wrapRefStore.current;
		const formRefDef = formRef || formRefStore.current;
		// Table height from bottom height-custom offset
		let paddingHeight = 30;
		let bottomIncludeBody = 0;
		if (wrapRefDef && isCanResizeParent) {
			const tablePadding = 12;
			const formMargin = 16;
			let paginationMargin = 10;
			const wrapHeight = wrapRefDef?.offsetHeight ?? 0;

			let formHeight = formRefDef?.offsetHeight ?? 0;
			if (formHeight) formHeight += formMargin;

			if (isBoolean(pagination) && !pagination) paginationMargin = 0;

			if (isBoolean(useSearchForm) && !useSearchForm) paddingHeight = 0;

			const headerCellHeight = (tableEl.querySelector(".ant-table-title") as HTMLElement)?.offsetHeight ?? 0;

			bottomIncludeBody = wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin;
		} else {
			// Table height from bottom
			bottomIncludeBody = getViewportOffset(headEl).bottomIncludeBody;
		}
		return {
			paddingHeight,
			bottomIncludeBody
		};
	}

	function calcTableHeight() {
		/**@updateBy-start:Jok-2024/12/03-11:34-修复窗口缩放时表格高度自适应未生效,是因为防抖函数生效时propsRef等皆为空，所以使用暂存数据 */
		const { maxHeight, resizeHeightOffset } = propsRef || propsRefStore.current;
		const tableData = getDataSourceRef || getDataSourceRefStore.current;
		const tableEl = tableElRef || tableElRefStore.current;

		if (!tableEl) return;

		if (!bodyEl) {
			bodyEl = tableEl.querySelector(".ant-table-body");
			if (!bodyEl) return;
		}

		handleScrollBar(bodyEl, tableEl);

		bodyEl!.style.height = "unset";

		if (!getCanResize || !tableData || tableData.length === 0) return;

		// Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight

		const headEl = tableEl.querySelector(".ant-table-thead");

		if (!headEl) return;

		const headerHeight = calcHeaderHeight(headEl);
		const footerHeight = caclFooterHeight(tableEl);
		const paginationHeight = caclPaginationHeight(tableEl);
		const { paddingHeight, bottomIncludeBody } = calcBottomAndPaddingHeight(tableEl, headEl);

		// not according to view height, only by table root element.
		let height = bottomIncludeBody - paddingHeight - headerHeight - footerHeight - paginationHeight - (resizeHeightOffset || 0);

		height = (height > maxHeight! ? (maxHeight as number) : height) ?? height;
		setHeight(height);
		bodyEl!.style.height = `${height}px`;
	}

	const getScrollX = useMemo(() => {
		let width = 0;
		if (rowSelectionRef) width += 60;

		// TODO props ?? 0;
		const NORMAL_WIDTH = 150;

		const columns = columnsRef.filter(item => !item.defaultHidden);

		columns.forEach(item => {
			width += Number.parseFloat(item.width as string) || 0;
		});
		const unsetWidthColumns = columns.filter(item => !Reflect.has(item, "width"));

		const len = unsetWidthColumns.length;
		if (len !== 0) width += len * NORMAL_WIDTH;

		const tableWidth = tableElRef?.offsetWidth ?? 0;

		return tableWidth > width ? "100%" : width;
	}, [columnsRef, tableElRef]);

	const getScrollRef = useMemo(() => {
		const { canResize, scroll } = propsRef;
		return {
			x: getScrollX,
			y: canResize ? tableHeightRef : null,
			scrollToFirstRowOnChange: false,
			...scroll
		};
	}, [tableHeightRef, propsRef.canResize, propsRef.scroll, getScrollX]);

	return { getScrollRef, redoHeight };
}
